#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>

#include "server.h"
#include "lprintf.h"
#include "child.h"

struct connection *client_conn = NULL;
struct server_global_conf *server_conf = NULL;

int get_listen_socket(int port)
{
     int sockfd = socket(AF_INET, SOCK_STREAM, 0);
     
     if (sockfd < 0)
     {
	  perror("socket");
	  return -1;
     }
     int flag = 1;
     if (setsockopt(sockfd, SOL_SOCKET, 
		    SO_REUSEADDR, &flag, sizeof(flag)))
     {
	  perror("setsockopt");
     }
     struct sockaddr_in localhost;
     
     memset((void*)&localhost, 0, sizeof(localhost));
     localhost.sin_family = AF_INET;
     localhost.sin_port = htons(port);

     int ret = bind(sockfd, (struct sockaddr*)&localhost, sizeof(localhost));
     if (ret < 0)
     {
	  perror("bind");
	  return -1;
     }

     ret = listen(sockfd, 64);
     if (ret < 0)
     {
	  perror("listen");
	  return -1;
     }

     return sockfd;
}

static void sigchld_handler(int signo)
{
     if (signo != SIGCHLD)
     {
	  lprintf("%s:%s Wrong signo %d\n", __FILE__,
		  __FUNCTION__, signo);
	  return;
     }

     int status;
     pid_t cpid;
     while(1)
     {
	   cpid = wait(&status);
	   if (cpid < 0 && errno == ECHILD)
	   {
		break;
	   }
	   lprintf("child[%d] exit with code: %d\n", cpid, status);
     }
     return;
}
int yaftp_main()
{
     /* init global server config */
     server_conf = malloc(sizeof(struct server_global_conf));
     server_conf->logs = stderr;
     server_conf->client_default_timeout = 600; /* 600 seconds */
     server_conf->welcome_msg = "220 Welcome to YAFtp Server 0.01\r\n";
     server_conf->listen_port = 4001;
     server_conf->pasv_min_port = 40001;
     server_conf->pasv_max_port = 40100;

     /* set SIG_CHLD signal handler */
//     signal(SIGCHLD, sigchld_handler);
     signal(SIGCHLD, SIG_IGN);
     /* start listen */
     int sockfd = get_listen_socket(server_conf->listen_port);

     if (sockfd == -1)
     {
	  exit(1);
     }

     struct sockaddr_in remotehost;
     memset((void*)&remotehost, 0, sizeof(remotehost));

     while (1)
     {
	  socklen_t  len = sizeof(remotehost);
	  int ret = accept(sockfd, (struct sockaddr*) &remotehost, &len);
	  
	  if (ret < 0)
	  {
	       if (EINTR == errno)
	       {
		    continue;
	       }
	       perror("accept");
	       return -1;
	  }

	  int childpid = 0;

	  if ((childpid = fork()) == 0)
	  {
	       /* child process */

	       /* init client connection struct */
	       lprintf("new process %d\n", getpid());
	       
	       client_conn = malloc(sizeof(struct connection));
	       memset(client_conn, 0, sizeof(struct connection));

	       client_conn->client_timeout = 
		    server_conf->client_default_timeout;
	       client_conn->cmdfd = ret;
	       /* call client handler */
	       child_init();
	       exit(0);
	  }
	  else if (childpid == -1)
	  {
	       lprintf("%s:%d fork error\n", __FUNCTION__, __LINE__);
	       lprintf("%s\n", strerror(errno));
	  }
	      
	  /* parent process, next loop */
     }
}
